﻿// MIT License
// 开源地址：https://gitee.com/co1024/AbcMvc
// Copyright (c) 2021-2023 1024
// Abc.Mvc=Furion+EF+SqlSugar+Pear layui admin.

using Microsoft.Extensions.Caching.Distributed;

namespace Abc.Core;

public class SysCacheService : ISysCacheService, ITransient
{
    private readonly IRepository<SysDataConfig> _dataConfigRepository;
    private readonly ILogger<SysCacheService> _logger;

    public SysCacheService(ILogger<SysCacheService> logger
        , IRepository<SysDataConfig> dataConfigRepository
    )
    {
        _logger = logger;
        _dataConfigRepository = dataConfigRepository;
    }

    /// <summary>
    ///     刷新缓存
    /// </summary>
    /// <param name="type">缓存类型</param>
    /// <returns></returns>
    public async Task<dynamic> RefreshCache(string type = "")
    {
        if (string.IsNullOrWhiteSpace(type))
        {
            await GetListByRoleAsync(true);
            await GetListAsync<SysMenu>(true);
            await GetListAsync<SysDataConfig>(true);

            await GetListAsync<EmailSendConfig>(true);
        }

        switch (type)
        {
            case "Menu": await GetListAsync<SysMenu>(true); break;
            case "DataConfig": await GetListAsync<SysDataConfig>(true); break;
            case "Role": await GetListByRoleAsync(true); break;
            case "EmailSendConfig": await GetListAsync<EmailSendConfig>(true); break; //邮件发送设置
        }

        return new { Succeeded = true, Errors = "刷新成功" };
    }

    /// <summary>
    ///     获取 实体的全部数据
    /// </summary>
    /// <typeparam name="TEntity">数据库表</typeparam>
    /// <returns></returns>
    public async Task<List<TEntity>> GetListAsync<TEntity>(bool isRefresh = false)
        where TEntity : class, IPrivateEntity, new()
    {
        (bool state, List<TEntity> list) result = await GetListCacheAsync<TEntity>(isRefresh);
        if (result.state) return result.list;
        //从数据库中读取数据
        return await _dataConfigRepository.Change<TEntity>().DetachedEntities.ToListWithCacheAsync();
    }

    #region menu

    /// <summary>
    ///     获取后台左侧菜单列表
    /// </summary>
    /// <param name="area">区域</param>
    /// <returns></returns>
    public async Task<List<PearMenuItemOut>> GetMenus(string area)
    {
        var entities = await GetListAsync<SysMenu>();
        var dbmenus = entities
            .Where(o => o.IsEnable && o.IsShow)
            .Select(o => new PearMenuItem
            {
                MenuType = o.MenuType,
                Code = o.Code,
                PCode = o.PCode,
                Name = o.Name,
                Icon = o.Icon,
                Sort = o.Sort,
                Url = o.Url
            }).ToList();
        var rmenus = dbmenus.GetMenus(area);
        return rmenus;
    }

    #endregion menu

    #region EmailSendConfig 邮箱发送配置

    /// <summary>
    ///     查询出指定邮箱的邮箱配置
    /// </summary>
    /// <param name="emailAccount">邮箱账号</param>
    /// <returns></returns>
    public async Task<EmailSendConfig> GetEmailSendConfig(string emailAccount)
    {
        var entities = await GetListAsync<EmailSendConfig>();
        return entities.FirstOrDefault(o => o.EmailAccount == emailAccount);
    }

    #endregion EmailSendConfig 邮箱发送配置

    /// <summary>
    ///     获取缓存
    /// </summary>
    /// <typeparam name="TEntity">实体</typeparam>
    /// <param name="isRefresh">是否刷新，刷新的话会移除缓存</param>
    /// <returns></returns>
    private async Task<(bool, List<TEntity>)> GetListCacheAsync<TEntity>(bool isRefresh = false)
    {
        if (isRefresh)
            Caches.Remove(Caches.GetTableCacheKey<TEntity>());
        else
        {
            //判断缓存中是否存在，存在直接返回
            var list = await Caches.GetAsync<List<TEntity>>(Caches.GetTableCacheKey<TEntity>());
            if (list != null && list.Any()) return (true, list);
        }

        return (false, null);
    }

    #region Role

    /// <summary>
    ///     获取角色列表或获取并刷新
    /// </summary>
    /// <param name="isRefresh"></param>
    /// <returns></returns>
    public async Task<List<SysRole>> GetListByRoleAsync(bool isRefresh = false)
    {
        (bool state, List<SysRole> list) result = await GetListCacheAsync<SysRole>(isRefresh);
        if (result.state) return result.list;

        var entities = await _dataConfigRepository.Change<SysRole>().DetachedEntities
            .Include(o => o.Menus)
            .ToListWithCacheAsync();
        return entities;
    }

    #endregion Role

    #region DataConfig

    /// <summary>
    ///     获取系统设置
    /// </summary>
    /// <returns></returns>
    public async Task<TEntity> GetSetting<TEntity>(string pkey) where TEntity : new()
    {
        var entities = await GetListAsync<SysDataConfig>();
        var settings = await entities.Where(o => o.PKey == pkey).ToListAsync();
        var settingdto = new TEntity();
        foreach (var setting in settings) settingdto.FieldSetValue(setting.Key, setting.Value);
        return settingdto;
    }

    /// <summary>
    ///     查询指定父级的所有下级
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="pkey">父级key</param>
    /// <returns></returns>
    public async Task<List<TEntity>> GetDataConfigEntitiesByPKey<TEntity>(string pkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var returnentities = entities.Where(o => !string.IsNullOrWhiteSpace(pkey) && o.PKey == pkey)
            .Adapt<List<TEntity>>();
        return returnentities;
    }

    /// <summary>
    ///     获取数据配置
    /// </summary>
    /// <param name="key"></param>
    /// <param name="pkey"></param>
    /// <returns></returns>
    public async Task<TEntity> GetDataConfigByKey<TEntity>(string key, string pkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var returnentitie = entities.FirstOrDefault(o =>
            !string.IsNullOrWhiteSpace(pkey) && !string.IsNullOrWhiteSpace(key) && o.PKey == pkey && o.Key == key);
        if (returnentitie == null) return default;
        return returnentitie.Adapt<TEntity>();
    }

    /// <summary>
    ///     查询一条
    /// </summary>
    /// <param name="id">ID</param>
    public async Task<TEntity> GetDataConfig<TEntity>(long id)
    {
        var dbentity = await GetListAsync<SysDataConfig>();
        if (dbentity == null) return default;
        return dbentity.Adapt<TEntity>();
    }

    /// <summary>
    ///     根据父ID 返回集合
    /// </summary>
    /// <param name="pid"></param>
    /// <returns></returns>
    public async Task<List<SysDataConfig>> GetDataConfigs(long pid)
    {
        var entities = await GetListAsync<SysDataConfig>();
        return await entities.Where(o => o.PId == pid).ToListAsync();
    }

    /// <summary>
    ///     根据分组 返回集合
    /// </summary>
    /// <param name="groupname"></param>
    /// <returns></returns>
    public async Task<List<SysDataConfig>> GetDataConfigs(string groupname)
    {
        var entities = await GetListAsync<SysDataConfig>();
        return await entities
            .Where(o => o.GroupName != null && o.GroupName.ToLower().Trim() == groupname.ToLower().Trim())
            .ToListAsync();
    }

    /// <summary>
    ///     获取父级
    /// </summary>
    /// <param name="groupname">分组</param>
    /// <param name="parentkey">父级Key</param>
    /// <returns></returns>
    public async Task<SysDataConfig> GetParentDataConfig(string groupname, string parentkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var entity = await entities.FirstOrDefaultAsync(o =>
            o.GroupName != null && o.Key != null && o.GroupName.Trim().ToLower() == groupname.Trim().ToLower() &&
            o.Key.Trim().ToLower() == parentkey.Trim().ToLower());
        return entity;
    }

    /// <summary>
    ///     获取 子集 DataConfig
    /// </summary>
    /// <param name="groupname">分组</param>
    /// <param name="childkey">子级Key</param>
    /// <returns></returns>
    public async Task<List<SysDataConfig>> GetChildDataConfigs(string groupname, string childkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var pdc = await entities.FirstOrDefaultAsync(o =>
            o.GroupName != null && o.Key != null && o.GroupName.Trim().ToLower() == groupname.Trim().ToLower() &&
            o.Key.Trim().ToLower() == groupname.Trim().ToLower());
        var dcs = await entities
            .Where(o => o.PId == pdc.Id && o.Key != null && o.Key.Trim().ToLower() == childkey.Trim().ToLower())
            .ToListAsync();
        return dcs;
    }

    /// <summary>
    ///     获取 子集 DataConfig
    /// </summary>
    /// <param name="groupname">分组</param>
    /// <returns></returns>
    public async Task<List<SysDataConfig>> GetChildDataConfigs(string groupname)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var pdc = await entities.FirstOrDefaultAsync(o =>
            o.GroupName != null && o.Key != null && o.GroupName.Trim().ToLower() == groupname.Trim().ToLower() &&
            o.Key.Trim().ToLower() == groupname.Trim().ToLower());
        var dcs = await entities.Where(o => o.PId == pdc.Id).ToListAsync();
        return dcs;
    }

    /// <summary>
    ///     获取 子集 DataConfig
    /// </summary>
    /// <param name="groupname">分组</param>
    /// <param name="childkey">子级Key</param>
    /// <returns></returns>
    public async Task<SysDataConfig> GetChildDataConfig(string groupname, string childkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        if (string.IsNullOrWhiteSpace(groupname) || string.IsNullOrWhiteSpace(childkey)) return null;
        var pdc = await entities.FirstOrDefaultAsync(o =>
            o.GroupName != null && o.Key != null && o.GroupName.Trim().ToLower() == groupname.Trim().ToLower() &&
            o.Key.Trim().ToLower() == groupname.Trim().ToLower());
        var dc = await entities
            .Where(o => o.PId == pdc.Id)
            .FirstOrDefaultAsync(o => o.Key != null && o.Key.Trim().ToLower() == childkey.Trim().ToLower());
        return dc;
    }

    /// <summary>
    ///     获取 子集 DataConfig
    /// </summary>
    /// <param name="groupname">分组</param>
    /// <param name="parentkey">父级Key</param>
    /// <param name="childkey">子级Key</param>
    /// <returns></returns>
    public async Task<SysDataConfig> GetChildDataConfig(string groupname, string parentkey, string childkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var pdc = await entities.FirstOrDefaultAsync(o =>
            o.GroupName != null && o.Key != null && o.GroupName.Trim().ToLower() == groupname.Trim().ToLower() &&
            o.Key.Trim().ToLower() == parentkey.Trim().ToLower());
        var dc = await entities
            .Where(o => o.PId == pdc.Id)
            .FirstOrDefaultAsync(o => o.Key != null && o.Key.Trim().ToLower() == childkey.Trim().ToLower());
        return dc;
    }

    #endregion DataConfig

    #region User  不用

    ///// <summary>
    ///// 缓存所有管理员
    ///// </summary>
    ///// <returns></returns>
    //public async Task<List<SysUser>> GetListByUserAsync(bool isRefresh = false)
    //{
    //    (bool state, List<SysUser> list) result = await GetListCacheAsync<SysUser>(isRefresh);
    //    if (result.state == true) return result.list;

    //    var entities = await _dataConfigRepository.Change<SysUser>().DetachedEntities
    //     .Include(o => o.Roles).ThenInclude(o => o.Menus)
    //     .ToListWithCacheAsync();
    //    return entities;
    //}

    #endregion User  不用

    #region 管理用户登陆

    /// <summary>
    ///     获取登陆的管理员用户
    /// </summary>
    /// <param name="userid"></param>
    /// <returns></returns>
    private async Task<SysUser> GetLoginAdminUser(long userid)
    {
        var entity = await _dataConfigRepository.Change<SysUser>().DetachedEntities
            .Include(o => o.Roles).ThenInclude(o => o.Menus)
            .FirstOrDefaultAsync(o => o.Id == userid);
        return entity;
    }

    /// <summary>
    ///     获取登陆的管理员用户
    /// </summary>
    /// <returns></returns>
    public async Task<SysUser> GetLoginAdminUser()
    {
        var userid = App.HttpContext.GetLoginUserId();
        if (userid > 0)
        {
            var user = await Caches.GetAsync<SysUser>(Caches.GetCacheKey($"User_{userid}"));
            if (user != null) return user;
            user = await GetLoginAdminUser(userid);
            if (user == null) await App.HttpContext?.SignOutAsync(AuthorizeType.AdminAuthenticationScheme);
            return user;
        }

        return default;
    }

    /// <summary>
    ///     刷新登陆管理用户缓存
    /// </summary>
    /// <param name="userid"></param>
    /// <returns></returns>
    public async Task RefreshLoginAdminUserCache(long userid)
    {
        // var entities = await GetListByUserAsync();
        var entity = await GetLoginAdminUser(userid);

        //判断下是否有此用户的缓存，有才设置
        var user = await Caches.GetAsync<SysUser>(Caches.GetCacheKey($"User_{userid}"));
        if (user == null) return;

        await SetLoginAdminUserCache(entity);
    }

    /// <summary>
    ///     移除登陆管理用户缓存
    /// </summary>
    /// <param name="userids"></param>
    /// <returns></returns>
    public async Task RemoveLoginAdminUserCache(List<long> userids)
    {
        foreach (var userid in userids) await RemoveLoginAdminUserCache(userid);
    }

    /// <summary>
    ///     移除登陆管理用户缓存
    /// </summary>
    /// <param name="userid"></param>
    /// <returns></returns>
    public async Task RemoveLoginAdminUserCache(long userid)
    {
        await Caches.RemoveAsync(Caches.GetCacheKey($"User_{userid}"));
    }

    /// <summary>
    ///     设置登陆管理用户缓存
    /// </summary>
    /// <param name="user"></param>
    /// <returns></returns>
    public async Task SetLoginAdminUserCache(SysUser user)
    {
        if (user == null) return;
        var loginuser = await GetLoginAdminUser(user.Id);
        await loginuser.SetCacheAsync(Caches.GetCacheKey($"User_{user.Id}"), new DistributedCacheEntryOptions
        {
            SlidingExpiration = TimeSpan.FromMinutes(30) //滑动过期时间
        });
    }

    /// <summary>
    ///     设置登陆管理用户缓存
    /// </summary>
    /// <param name="userId"></param>
    /// <returns></returns>
    public async Task SetLoginAdminUserCache(long userId)
    {
        var loginuser = await GetLoginAdminUser(userId);
        await loginuser.SetCacheAsync(Caches.GetCacheKey($"User_{loginuser.Id}"), new DistributedCacheEntryOptions
        {
            SlidingExpiration = TimeSpan.FromMinutes(30) //滑动过期时间
        });
    }

    /// <summary>
    ///     验证权限
    /// </summary>
    /// <param name="permissionType">权限类型</param>
    /// <param name="controller"></param>
    /// <param name="action"></param>
    /// <param name="userid"></param>
    /// <returns></returns>
    public async Task<bool> HasAuthorize(string permissionType, string controller, string action, long userid = 0)
    {
        if (userid <= 0) userid = App.HttpContext.GetLoginUserId();
        var user = await Caches.GetAsync<SysUser>(Caches.GetCacheKey($"User_{userid}"));
        if (user == null)
        {
            //var context = App.GetService<IHttpContextAccessor>();
            //var a = context.GetCookiesValue<long>($"User_{userid}");
            // var entities = await GetListByUserAsync();
            user = await GetLoginAdminUser(userid);
            if (user == null) return false;

            if (user.IsEnable == false)
            {
                //登出 账号失效
                await App.HttpContext.SignOutAsync(AuthorizeType.AdminAuthenticationScheme);
                return false; //用户没启用，没有权限
            }

            await SetLoginAdminUserCache(user);
            //return false;
        }
        else if (user.IsEnable == false)
        {
            //登出 账号失效
            await App.HttpContext.SignOutAsync(AuthorizeType.AdminAuthenticationScheme);
            return false; //用户没启用，没有权限
        }

        //administrator 与developer 不验证权限
        if (user.Account.ToLower().Trim() == "administrator".ToLower().Trim() ||
            user.Account.ToLower().Trim() == "developer".ToLower().Trim()) return true;
        if (user.Roles == null) return false;
        foreach (var role in user.Roles)
        {
            var isHasAuthorize = role.Menus.Any(o =>
                o.Controller != null && o.Actions != null &&
                o.Controller.ToLower().Trim() == controller.Trim().ToLower() &&
                o.Actions.ToLower().Trim().Contains(action.ToLower().Trim()));
            if (isHasAuthorize) return true;
        }

        return false;
    }

    #endregion 管理用户登陆
}